#pragma once

#include "stdafx.h"

#include "Win32Helper.h"

#define PCWINNT_SYS
#include <array>
#include <vector>
#include <map>
#include <list>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <cctype>
#include <atltime.h>
#include <Shlwapi.h>
#include <atlconv.h>

#include "AnsysModel.h"

using Win32Helper::CDirectory;

extern "C"
{
#include <cAnsInterface.h>
#include <cAnsQuery.h>
};
#pragma comment(lib,"ansys.lib")

#pragma region Helper functions
//const char ENDLINE = '\n';

inline bool IsEqual(double v1, double v2)
{
	const double eps = 1.0e-6;
	double delta = v1 - v2;
	return (-eps < delta) && (delta < eps);
}

template< typename T >
bool StrToNum(const std::string& str, T& num)
{
	std::istringstream iss(str);
	return !(iss >> num).fail();
}

void printString(LPCTSTR str)
{
	ATL::CW2A astr(str);
	cAns_printf((LPSTR)astr);
	cAns_printf("\n");
}

inline bool IsAlphabetic(CHAR c)
{
	return ('a' <= c && c <= 'z')
		|| ('A' <= c && c <= 'Z')
		|| ('0' <= c && c <= '9')
		|| (c == '~')
		|| (c == '-')
		|| (c == '_');
}

inline bool IsAlphabetic(WCHAR c)
{
	return ('a' <= c && c <= 'z')
		|| ('A' <= c && c <= 'Z')
		|| ('0' <= c && c <= '9')
		|| (c == '~')
		|| (c == '-')
		|| (c == '_');
}

ATL::CStringA TrimNonAlphabetic(const ATL::CStringA& str)
{
	if (str.GetLength()<1)
		return "";

	int start = 0;
	auto c = str[start];
	while (!IsAlphabetic(c))
	{
		++start;
		if (start>(str.GetLength() - 1))
			break;

		c = str[start];
	}

	int end = str.GetLength() - 1;
	c = str[end];
	while (!IsAlphabetic(c))
	{
		--end;
		if (end<0)
			break;

		c = str[end];
	}

	return ((start <= end) ? str.Mid(start, (end - start + 1)) : "");
}

ATL::CString TrimNonAlphabetic(const ATL::CString& str)
{
	if (str.GetLength() < 1)
		return L"";

	int start = 0;
	auto c = str[start];
	while (!IsAlphabetic(c))
	{
		++start;
		if (start > (str.GetLength() - 1))
			break;

		c = str[start];
	}

	int end = str.GetLength() - 1;
	c = str[end];
	while (!IsAlphabetic(c))
	{
		--end;
		if (end < 0)
			break;

		c = str[end];
	}

	return ((start <= end) ? str.Mid(start, (end - start + 1)) : L"");
}

void ToLower(char* str)
{
	for (int i = 0; str[i] != '\0'; i++)
	{
		str[i] = static_cast<char>(tolower(str[i]));
	}
}

std::string CStringToString(const ATL::CString& cstr)
{
	if (cstr.IsEmpty())
		return std::string("");

	ATL::CW2A acstr(cstr);
	std::string str((LPCSTR)acstr);
	return str;
}

ATL::CString StringToCString(const std::string& str)
{
	if (str.empty())
		return ATL::CString(L"");

	ATL::CString cstr(str.c_str());
	return cstr;
}

std::string GetAppVersionString()
{
	CTime buildDate = Win32Helper::CVersionInfo::GetBuildDate();
	char verStr[128] = { 0 };
	sprintf_s(verStr, "%4d.%02d.%02d",
		buildDate.GetYear(), buildDate.GetMonth(), buildDate.GetDay());
	return std::string(verStr);
}

std::string GetCurrentTimeString()
{
	CTime ct = CTime::GetCurrentTime();
	char timeStr[128] = { 0 };
	sprintf_s(timeStr, "%4d.%02d.%02d %02d:%02d:%02d", ct.GetYear(), ct.GetMonth(), ct.GetDay(),
		ct.GetHour(), ct.GetMinute(), ct.GetSecond());
	return std::string(timeStr);
}

void PrintString(const std::string& str)
{
	char cmdBuf[1024];
	int j = 0;
	for (size_t i = 0; i < str.size(); i++)
	{
		cmdBuf[j] = str[i];
		if (cmdBuf[j] == ENDLINE)
		{
			cmdBuf[j + 1] = '\0';
			::cAns_printf(cmdBuf);
			j = 0;
		}
		else
		{
			++j;
		}
	}
}

void PrintString(const char* str)
{
	PrintString(std::string{ str });
}

void PrintDebugString(const std::string& debugString)
{
#ifdef _DEBUG
	PrintString(debugString);
#endif // _DEBUG
}

void PrintAppVersionInfo()
{
	char verInfo[128] = { 0 };
	auto verStr = GetAppVersionString();
	sprintf_s(verInfo, "***** AnsysExporter v%s by wudong(wdhust@gmail.com) *****\n", verStr.c_str());
	char splitLine[] = "*****************************************************************\n";
	cAns_printf("\n\n");
	cAns_printf(splitLine);
	cAns_printf(verInfo);
	cAns_printf(splitLine);
	cAns_printf("\n\n");
};

void NormalizePathStr(std::string& pathStr)
{
	auto len = pathStr.size();
	if (pathStr[len - 1] != '\\')
	{
		pathStr += '\\';
	}
}

std::string PathCanonicalize(const std::string& path)
{
	CHAR pathDest[MAX_PATH];
	::PathCanonicalizeA(pathDest, path.c_str());
	return std::string{ pathDest };
}

std::string PathCombine(const std::string& path1, const std::string& path2)
{
	CHAR pathDest[MAX_PATH];
	::PathCombineA(pathDest, path1.c_str(), path2.c_str());
	return std::string{ pathDest };
}

bool IsDirectoryExists(const std::string& dirPath)
{
	DWORD dwAttrib = GetFileAttributesA(dirPath.c_str());
	return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
		(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}

#pragma endregion

#ifdef _DEBUG
#define PrintCurrentLineInfo() cAns_printf(">>>>>>>> current line = %d\n", __LINE__);
#else
#define PrintCurrentLineInfo() {};
#endif

